/****************************************************************************
 *
 * This file is part of the CodeMax editor support code.
 *
 * Primary author: Christopher J. Cason.
 *
 * from Persistence of Vision(tm) Ray Tracer version 3.6.
 * Copyright 1991-2003 Persistence of Vision Team
 * Copyright 2003-2004 Persistence of Vision Raytracer Pty. Ltd.
 *---------------------------------------------------------------------------
 * NOTICE: This source code file is provided so that users may experiment
 * with enhancements to POV-Ray and to port the software to platforms other
 * than those supported by the POV-Ray developers. There are strict rules
 * regarding how you are permitted to use this file. These rules are contained
 * in the distribution and derivative versions licenses which should have been
 * provided with this file.
 *
 * These licences may be found online, linked from the end-user license
 * agreement that is located at http://www.povray.org/povlegal.html
 *---------------------------------------------------------------------------
 * This program is based on the popular DKB raytracer version 2.12.
 * DKBTrace was originally written by David K. Buck.
 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
 *---------------------------------------------------------------------------
 * Thanks to WinMain Software (http://www.winmain.com/) for providing the (at
 * the time commercial) CodeMax edit control which the POVWIN editor is based.
 *---------------------------------------------------------------------------
 * $File: //depot/misc/win-sourcedist/codemax/PrintOptions.cpp $
 * $Revision: #1 $
 * $Change: 2944 $
 * $DateTime: 2004/07/05 13:11:12 $
 * $Author: chrisc $
 * $Log$
 *****************************************************************************/

#include <vcl.h>
#pragma hdrstop

#include "EditForm.h"
#include "PrintOptions.h"
#include "Printers.hpp"
//----------------------------------------------------------------------------
#pragma link "cspin"
#pragma resource "*.dfm"
TPrintForm *PrintForm;
//----------------------------------------------------------------------------
__fastcall TPrintForm::TPrintForm(TComponent *Owner) : TForm(Owner)
{
  FPrinting = false ;
  FCancel = false ;
}

//----------------------------------------------------------------------------
void __fastcall TPrintForm::ChooseButtonClick(TObject *Sender)
{
  if (FontDialog->Execute ())
    FontSampleLabel->Font->Assign (FontDialog->Font) ;
}

//---------------------------------------------------------------------------
void __fastcall TPrintForm::FormShow(TObject *Sender)
{
  EditTagStruct         *t = (EditTagStruct *) e->Tag ;

  FontSampleLabel->Font->Assign (FontDialog->Font) ;
  SourceFileLabel->Caption = AnsiString ("Source File: ") + t->ShortName ;
  PrintMarkedBlock->Enabled = e->CanCut ;
  PrintMarkedBlock->Checked = PrintMarkedBlock->Enabled ;
}

//---------------------------------------------------------------------------
void __fastcall TPrintForm::SetupButtonClick(TObject *Sender)
{
  SetupDialog->Execute () ;
}

//---------------------------------------------------------------------------
void __fastcall TPrintForm::CancelButtonClick(TObject *Sender)
{
  FCancel = true ;
  Hide () ;
}

//---------------------------------------------------------------------------
void __fastcall TPrintForm::PrintButtonClick(TObject *Sender)
{
  PrintFile () ;
  Hide () ;
}

//---------------------------------------------------------------------------
void __fastcall TPrintForm::FormKeyPress(TObject *Sender, char &Key)
{
  if (Key == '\x1b')
  {
    FCancel = true ;
    Hide () ;
  }
  else if (Key == '\x0d')
    PrintButtonClick (PrintButton) ;
}

//---------------------------------------------------------------------------
void __fastcall TPrintForm::FormClose(TObject *Sender, TCloseAction &Action)
{
  FCancel = true ;
}

//---------------------------------------------------------------------------
void __fastcall TPrintForm::FormHide(TObject *Sender)
{
  FCancel = true ;
}

//---------------------------------------------------------------------------
AnsiString TabExpand (AnsiString str, int width)
{
  int                   pos ;
  AnsiString            result ;

  if (str.Pos ("\t") == 0)
    return (str) ;
  result = str ;
  while ((pos = result.Pos ("\t")) != 0)
  {
    if (pos % width)
    {
      result.Delete (pos, 1) ;
      result.Insert (AnsiString::StringOfChar (' ', width - pos % width + 1), pos) ;
    }
    else
      result [pos] = ' ' ;
  }
  return (result) ;
}

//---------------------------------------------------------------------------
void TPrintForm::PrintFile (void)
{
  int                   pageHeight ;
  int                   pageWidth ;
  int                   lineHeight ;
  int                   ppi ;
  int                   leftMargin ;
  int                   topMargin ;
  int                   rightMargin ;
  int                   bottomMargin ;
  int                   pageNo = 1 ;
  int                   firstLine = 1 ;
  int                   firstCol = 1 ;
  int                   lastLine ;
  int                   lastCol = -1 ;
  int                   textWidth ;
  int                   charWidth ;
  int                   line ;
  int                   maxChars ;
  int                   commentPos ;
  int                   pos ;
  int                   tabWidth ;
  int                   printableWidth ;
  char                  linestr [9] ;
  bool                  ok = false ;
  bool                  noWrap = !WrapLines->Checked ;
  bool                  lineNumbers = LineNumbers->Checked ;
  bool                  newLine = true ;
  bool                  pageBreaks = PageBreaks->Checked ;
  bool                  highlight = HighlightComments->Checked ;
  bool                  isComment = false ;
  bool                  pageBreak = false ;
  TRect                 rect ;
  TPrinter              *p = Printer () ;
  CM_RANGE              sel ;
  AnsiString            currentLine ;
  AnsiString            header ;
  AnsiString            str ;
  EditTagStruct         *t = (EditTagStruct *) e->Tag ;

  FCancel = false ;
  FPrinting = true ;
  p->Canvas->Font->Assign (PrintForm->FontDialog->Font) ;
  p->Canvas->Font->Color = clBlack ;
  if (PrintMarkedBlock->Enabled && PrintMarkedBlock->Checked)
  {
    e->GetSel (&sel) ;
    firstLine = sel.posStart.nLine + 1 ;
    lastLine = sel.posEnd.nLine + 1 ;
    firstCol = sel.posStart.nCol + 1 ;
    lastCol = sel.posEnd.nCol + 1 ;
  }
  else
    lastLine = e->LineCount ;

  try
  {
    // need to call BeginDoc () before getting PPI
    p->Title = t->ShortName ;
    p->BeginDoc () ;
    lineHeight = p->Canvas->TextHeight ("My") ;
    charWidth = p->Canvas->TextWidth (" ") ;
    pageWidth = p->PageWidth ;
    pageHeight = p->PageHeight ;
    ppi = p->Canvas->Font->PixelsPerInch ;
    leftMargin = LeftMargin->Value * ppi / 26 ;
    topMargin = TopMargin->Value * ppi / 26 ;
    rightMargin = RightMargin->Value * ppi / 26 ;
    bottomMargin = BottomMargin->Value * ppi / 26 ;
    printableWidth = pageWidth - rightMargin - leftMargin ;
    p->Canvas->Pen->Color = clBlack ;
    p->Canvas->Pen->Width = 1 ;
    p->Canvas->Pen->Style = psSolid ;
    rect.Left = leftMargin ;
    rect.Right = p->PageWidth - rightMargin ;
    rect.Top = topMargin ;
    rect.Bottom = rect.Top + lineHeight ;
    maxChars = (rect.Right - rect.Left + 1) / charWidth ;
    if (TwoUpPrinting->Checked)
    {
      rect.Right = rect.Left + printableWidth / 2 - charWidth / 2 ;
      maxChars /= 2 ;
      p->Canvas->MoveTo (pageWidth / 2, topMargin + (Header->Checked ? lineHeight * 3 / 2 : 0)) ;
      p->Canvas->LineTo (pageWidth / 2, pageHeight - bottomMargin) ;
    }
    tabWidth = e->TabSize ;

    line = firstLine ;
    currentLine = TabExpand (e->Lines [firstLine], tabWidth).TrimRight () ;
    InfoLabel->Caption = AnsiString ("1 of ") + (lastLine - firstLine + 1) ;
    MessagePanel->Visible = true ;

    while (line <= lastLine)
    {
      if (FCancel)
        break ;

      if (line % 9 == 1)
      {
        InfoLabel->Caption = AnsiString (line - firstLine) + " of " + (lastLine - firstLine + 1) ;
        Application->ProcessMessages () ;
      }

      if (currentLine.Pos ("\x0c"))
      {
        while ((pos = currentLine.Pos ("\x0c")) != 0)
          currentLine.Delete (pos, 1) ;
        if (pageBreaks)
        {
          pageBreak = true ;
          if (currentLine.Trim ().IsEmpty ())
          {
            currentLine = TabExpand (e->Lines [++line], tabWidth).TrimRight () ;
            newLine = true ;
            isComment = false ;
          }
        }
      }

      if (pageBreak || (rect.Bottom > pageHeight - bottomMargin))
      {
        rect.Top = topMargin ;
        rect.Bottom = rect.Top + lineHeight ;
        if (TwoUpPrinting->Checked)
        {
          if (pageNo % 2 == 0)
          {
            rect.Left = leftMargin ;
            rect.Right = rect.Left + printableWidth / 2 - charWidth / 2 ;
            p->NewPage () ;
            p->Canvas->MoveTo (pageWidth / 2, topMargin +  (Header->Checked ? lineHeight * 3 / 2 : 0)) ;
            p->Canvas->LineTo (pageWidth / 2, pageHeight - bottomMargin) ;
          }
          else
          {
            rect.Left = leftMargin + printableWidth / 2 + charWidth / 2 ;
            rect.Right = pageWidth - rightMargin ;
          }
        }
        else
          p->NewPage () ;
        pageNo++ ;
        pageBreak = false ;
      }

      currentLine = currentLine.TrimRight () ;

      if (rect.Top == topMargin && Header->Checked)
      {
        TRect r = rect ;
        r.Bottom += lineHeight / 8 ;
        p->Canvas->Brush->Style = bsSolid ;
        p->Canvas->Brush->Color = TColor (0xE0E0E0) ;
        p->Canvas->RoundRect (r.Left, r.Top, r.Right, r.Bottom, lineHeight / 3, lineHeight / 3) ;
        r = rect ;
        r.Left += charWidth / 2 ;
        r.Right -= charWidth / 2 ;
        r.Top += lineHeight / 8 ;
        header = AnsiString (" Page ") + pageNo ;
        if (t->LongName.Length () + header.Length () >= maxChars)
        {
          str = t->LongName ;
          str.Delete (1, header.Length () + str.Length () - maxChars + 4) ;
          str.Insert ("...", 1) ;
          p->Canvas->TextRect (r, r.Left, r.Top, str) ;
        }
        else
          p->Canvas->TextRect (r, r.Left, r.Top, t->LongName) ;
        textWidth = p->Canvas->TextWidth (header) ;
        r.Left = r.Right - textWidth ;
        p->Canvas->TextRect (r, r.Left, r.Top, header) ;
        rect.Top += lineHeight * 3 / 2 ;
        rect.Bottom = rect.Top + lineHeight ;
        p->Canvas->Brush->Style = bsClear ;
      }

      if (line == lastLine && lastCol != -1)
        currentLine = currentLine.SubString (1, lastCol) ;
      if (line == firstLine && firstCol != 1)
        currentLine = currentLine.SubString (firstCol, currentLine.Length ()) ;

      if (lineNumbers)
      {
        if (newLine)
        {
          wsprintf (linestr, "%-4d ", line) ;
          currentLine.Insert (linestr, 1) ;
        }
        else
          currentLine.Insert ("     ", 1) ;
      }

      str = currentLine.SubString (1, maxChars) ;
      currentLine.Delete (1, maxChars) ;
      p->Canvas->TextRect (rect, rect.Left, rect.Top, str) ;

      if (highlight)
      {
        commentPos = lineNumbers ? 6 : 1 ;
        // look for a comment, but ignore '://'-style constructs.
        // ('://' is probably part of a URI of some sort).
        if (!isComment)
          if ((isComment = (commentPos = str.Pos ("//"))) != 0)
            if (commentPos > 1)
              if (str [commentPos - 1] == ':')
                isComment = false ;
        if (isComment)
        {
          TRect r = rect ;
          p->Canvas->Brush->Style = bsSolid ;
          p->Canvas->Brush->Color = TColor (0xE0E0E0) ;
          r.Left += --commentPos * charWidth ;
          str.Delete (1, commentPos) ;
          r.Right = r.Left + str.Length () * charWidth ;
          if (r.Right > rect.Right)
            r.Right = rect.Right ;
          p->Canvas->TextRect (r, r.Left, r.Top, str) ;
          p->Canvas->Brush->Style = bsClear ;
        }
      }

      rect.Top += lineHeight ;
      rect.Bottom += lineHeight ;

      if (noWrap || currentLine.IsEmpty ())
      {
        currentLine = TabExpand (e->Lines [++line], tabWidth).TrimRight () ;
        newLine = true ;
        isComment = false ;
      }
      else
        newLine = false ;
    }
    MessagePanel->Visible = false ;
    ok = true ;
  }
  catch (Exception &E)
  {
    ShowMessage (AnsiString (E.ClassName ()) + ": " + E.Message) ;
  }
  if (!ok || FCancel)
    p->Abort () ;
  else
    p->EndDoc () ;
  FPrinting = false ;
}

//---------------------------------------------------------------------------
void __fastcall TPrintForm::TwoUpPrintingClick(TObject *Sender)
{
  if (TwoUpPrinting->Checked)
    if (Printer ()->Orientation != poLandscape)
      if (!Visible || MessageBox (Handle, "Set Landscape mode ?", "Two-Up Printing", MB_YESNO) == IDYES)
        Printer ()->Orientation = poLandscape ;
  if (!TwoUpPrinting->Checked)
    if (Printer ()->Orientation != poPortrait)
      if (!Visible || MessageBox (Handle, "Set Portrait mode ?", "One-Up Printing", MB_YESNO) == IDYES)
        Printer ()->Orientation = poPortrait ;
}

//---------------------------------------------------------------------------

void __fastcall TPrintForm::FormCreate(TObject *Sender)
{
  MessagePanel->BringToFront () ;
}
//---------------------------------------------------------------------------

